﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.ServiceProcess;
using System.Web.Script.Serialization;
using System.Windows.Forms;

namespace VOEISHubPushServiceClient
{
    public partial class Form1 : Form
    {
        
        private FormDirtyTracker _dirtyTracker;
        private int _evtLogThreadCount = 0;
        private bool _closeRequested = false;
        ShutDown frmShutDown = new ShutDown();

       

        public Form1()
        {
            InitializeComponent();
        }

        #region Form Actions

        private void Form1_Load(object sender, EventArgs e)
        {
            //Set up our picture box correctly since I can't access the parent settings through the graphical IDE
            pbEventLogLoading.BackColor = System.Drawing.Color.Transparent;
            pbEventLogLoading.Parent = dataGridView1;
            pbEventLogLoading.Location = new Point((dataGridView1.Width / 2) - 50, (dataGridView1.Height / 2) - 50);

            //Set up our service controller so we can start and stop the service from the client
            ServiceController myController = new ServiceController("VOEIS Hub Push Service", System.Environment.MachineName.ToString());

            //Enable and start our timer
            timer1.Enabled = true;
            timer1_Tick(timer1, EventArgs.Empty);

            //Initialize a new dirty tracker so we can track whether anything has changed on the form
            _dirtyTracker = new FormDirtyTracker(this);

            //Populate our configuration values
            PopulateConfiguration();
        }        

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            _closeRequested = true;

            if (_dirtyTracker.IsDirty)
            {
                DialogResult result = MessageBox.Show("Changes have been made - do you wish to save them before exiting?", "Changes Detected", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
                if (result == DialogResult.Yes)
                {
                    //Save all of the settings.
                    SaveConfiguration();

                    //Clear our dirty tracker
                    _dirtyTracker.IsDirty = false;
                }
                else
                {
                    _dirtyTracker.IsDirty = false;
                }
            }

            //Make sure that we don't have any errant threads running, and if so, then wait on them
            if (_evtLogThreadCount > 0)
            {
                e.Cancel = true;
                Rectangle recScreen = Screen.GetWorkingArea(this);
                this.Hide();
                frmShutDown.Show();
                frmShutDown.Location = new Point((recScreen.Width/2)-(frmShutDown.Width/2),(recScreen.Height / 2) - (frmShutDown.Height / 2));
            }
            else
            {
                e.Cancel = false;
                //TODO: I need to make some adjustments here because if the form waits and there are changes then the user gets two dialogs
                frmShutDown.Close();
            }
        }        

        private void timer1_Tick(object sender, EventArgs e)
        {
            try
            {
                ServiceController myController = new ServiceController("VOEIS Hub Push Service", System.Environment.MachineName.ToString());
                tslblStatusValue.Text = myController.Status.ToString();
                if (myController.Status == ServiceControllerStatus.StartPending || myController.Status == ServiceControllerStatus.StopPending)
                {
                    btnStartService.Enabled = false;
                    btnStopService.Enabled = false;
                    tslblStatusValue.ForeColor = Color.DarkOrange;
                }
                else if (myController.Status == ServiceControllerStatus.Running)
                {
                    btnStartService.Enabled = false;
                    btnStopService.Enabled = true;
                    tslblStatusValue.ForeColor = Color.Green;
                }
                else if (myController.Status == ServiceControllerStatus.Stopped)
                {
                    btnStartService.Enabled = true;
                    btnStopService.Enabled = false;
                    tslblStatusValue.ForeColor = Color.Red;
                }
            }
            catch (InvalidOperationException)
            {
                timer1.Stop();
                MessageBox.Show("The VOEIS Push Service is missing.  Please uninstall and reinstall the service and application.", "Service Unavailable", MessageBoxButtons.OK, MessageBoxIcon.Error);
                tslblStatusValue.Text = "Service Unavailable";
                tslblStatusValue.ForeColor = Color.Red;

            }
            catch (Exception ex)
            {
                timer1.Stop();
                MessageBox.Show(ex.Message.ToString());
                tslblStatusValue.Text = "Service Unavailable";
                tslblStatusValue.ForeColor = Color.Red;
            }
        }

        #endregion

        #region Menu Items

        //TODO: This call should probably run in a separate thread.
        private void getProjectDataTemplatesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            SQLCommunicator sqlComm = new SQLCommunicator();
            VOEISHubAPI hubAPI = new VOEISHubAPI();

            string projectTemplates = "";
            try
            {
                ArrayList projectIDs = sqlComm.ListProjectIDs();

                for (Int32 i = 0; i < projectIDs.Count; i++)
                {
                    projectTemplates = "********** Project ID " + projectIDs[i].ToString() + " **********";
                    projectTemplates += System.Environment.NewLine + hubAPI.GetProjectTemplates(projectIDs[i].ToString()) + Environment.NewLine;
                }

                APIResults apiRslts = new APIResults(projectTemplates);
                apiRslts.ShowDialog();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString(), "Error executing API call", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }

        }

        private void saveEncryptedConfigurationToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveEncryptedTemplateConfigDialog.ShowDialog();
        }

        private void saveEncryptedTemplateConfigDialog_FileOk(object sender, CancelEventArgs e)
        {
            //Check if the form is dirty, and if so, prompt for a save before saving the template
            if (_dirtyTracker.IsDirty == true)
            {
               DialogResult response = new DialogResult();
                response = MessageBox.Show("You must save your changes before saving this template.", "Changes detected", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
                if (response == System.Windows.Forms.DialogResult.OK)
                {
                    //Save the template
                    SaveConfiguration();
                }
                else
                {
                    MessageBox.Show("Save aborted!", "Aborted", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }  
            }
                    
            //Save the template
            ServiceConfigurationManager scm = new ServiceConfigurationManager();
            scm.SaveTemplate(Properties.Settings.Default.VOEISHubPushServicePath, saveEncryptedTemplateConfigDialog.FileName, true);                           
              
        }

        private void loadConfigurationToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                //TODO: open a file dialog
                OpenFileDialog ofd = new OpenFileDialog();
                ofd.Filter = "Configuration Files|*.exe.config";
                ofd.ShowDialog();
                if (!File.Exists(ofd.FileName.ToString()))
                {
                    MessageBox.Show("Configuration file required :" + ofd.FileName, "File Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                string configTemplatePath = ofd.FileName.ToString();
                ServiceConfigurationManager scm = new ServiceConfigurationManager();
                scm.LoadTemplate(this, configTemplatePath);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString(), "Error loading configuration template.", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox1 abtBox = new AboutBox1();
            abtBox.ShowDialog();
        }

        private void saveConfigurationSettingsToServiceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveConfiguration();
        }

        private void exportConfigurationAsTemplateunencryptedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            saveUnencryptedTemplateConfigDialog.ShowDialog();
        }

        private void saveUnencryptedTemplateConfigDialog_FileOk(object sender, CancelEventArgs e)
        {
            //Check if the form is dirty, and if so, prompt for a save before saving the template
            if (_dirtyTracker.IsDirty == true)
            {
                DialogResult response = new DialogResult();
                response = MessageBox.Show("You must save your changes before saving this template.", "Changes detected", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
                if (response == System.Windows.Forms.DialogResult.OK)
                {
                    //Save the template
                    SaveConfiguration();
                }
                else
                {
                    MessageBox.Show("Save aborted!", "Aborted", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }
            }

            ServiceConfigurationManager scm = new ServiceConfigurationManager();
            scm.SaveTemplate(Properties.Settings.Default.VOEISHubPushServicePath, saveUnencryptedTemplateConfigDialog.FileName, false);
        }

        #endregion
        
        #region Service Control

        private void btnStartService_Click(object sender, EventArgs e)
        {
            ServiceController myController = new ServiceController("VOEIS Hub Push Service", System.Environment.MachineName.ToString());
            try
            {
                //Start the service
                myController.Start();      
          
                //Update the log
                StartEventLogThread();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }

            finally
            {
        
                tslblStatusValue.Text = myController.Status.ToString();
                Application.DoEvents();
            }

            }

        //TODO: I need to find a better way to kill child threads other than just waiting for them
        private void btnStopService_Click(object sender, EventArgs e)
        {
            ServiceController myController = new ServiceController("VOEIS Hub Push Service", System.Environment.MachineName.ToString());
            try
            {
                //Stop the service
                myController.Stop();

                //Update the log
                StartEventLogThread();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
            finally
            {
                tslblStatusValue.Text = myController.Status.ToString();
                Application.DoEvents();
            }
        }

        private void btnServiceUndo_Click(object sender, EventArgs e)
        {
            PopulateServiceControlTab();
        }

        #endregion

        #region Service Database Settings

        private void radServiceWindowsAuthentication_CheckedChanged(object sender, EventArgs e)
        {
            if (radServiceWindowsAuthentication.Checked == true)
            {
                lblServiceConnectionString.Text = "Data Source=" + cboServiceSQLServer.Text + ";Initial Catalog=" + cboServiceDatabase.Text + ";Integrated Security=SSPI;";
                txtServiceDatabaseUserName.Enabled = false;
                txtServiceDatabasePassword.Enabled = false;
            }
            else
            {
                lblServiceConnectionString.Text = "Data Source=" + cboServiceSQLServer.Text + ";Initial Catalog=" + cboServiceDatabase.Text + ";User Id=" + txtServiceDatabaseUserName.Text + ";Password=**********;";
                txtServiceDatabaseUserName.Enabled = true;
                txtServiceDatabasePassword.Enabled = true;
            }
        }

        private void cboServiceSQLServer_DropDown(object sender, EventArgs e)
        {
            //TODO: Add code to enumerate the servers on the network.
            if (cboServiceSQLServer.Items.Count == 0)
            {
                this.Cursor = Cursors.WaitCursor;
                cboServiceSQLServer.Items.Clear();

                SQLCommunicator communicator = new SQLCommunicator();
                DataTable table;
                String ServerName = "";

                table = communicator.ListSqlInstances();

                foreach (System.Data.DataRow row in table.Rows)
                {
                    ServerName = "";
                    ServerName = row[0].ToString();
                    if (row[1].ToString() != null)
                    {
                        ServerName += "\\" + row[1].ToString();
                    }
                    cboServiceSQLServer.Items.Add(row[0].ToString() + "\\" + row[1].ToString());
                }
                this.Cursor = Cursors.Default;
            }
        }

        private void cboServiceSQLServer_TextChanged(object sender, EventArgs e)
        {
            cboServiceDatabase.Items.Clear();
            cboServiceDatabase.ResetText();
            radServiceWindowsAuthentication_CheckedChanged(sender, e);
        }

        private void cboServiceDatabase_TextChanged(object sender, EventArgs e)
        {
            radServiceWindowsAuthentication_CheckedChanged(sender, e);
        }

        private void cboServiceDatabase_DropDown(object sender, EventArgs e)
        {
            try
            {
                if (cboServiceSQLServer.SelectedText != null)
                {
                    //Change the cursor to signify the work being done
                    this.Cursor = Cursors.WaitCursor;

                    //Clear the combobox
                    cboServiceDatabase.Items.Clear();

                    SQLCommunicator communicator = new SQLCommunicator();
                    DataTable table = new DataTable();

                    if (radServiceWindowsAuthentication.Checked == true)
                    {
                        //TODO: If a user enters incorrect server parameters, this crashes with a NullReferenceException
                        table = communicator.ListSQLDatabases();
                    }
                    else
                    {
                        if (txtServiceDatabaseUserName.TextLength > 0 && txtServiceDatabaseUserName.TextLength > 0)
                        {
                            table = communicator.ListSQLDatabases();
                        }
                        else
                        {
                            MessageBox.Show("You must enter a username and password to continue, or choose a different authentication method.");
                            this.Cursor = Cursors.Default;
                            return;
                        }
                    }

                    foreach (System.Data.DataRow row in table.Rows)
                    {
                        cboServiceDatabase.Items.Add(row[0].ToString());
                    }

                }
                else
                {
                    MessageBox.Show("You must select a database first.");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        private void txtServiceDatabaseUserName_TextChanged(object sender, EventArgs e)
        {
            radServiceWindowsAuthentication_CheckedChanged(sender, e);
        }

        private void btnServiceDBUndo_Click(object sender, EventArgs e)
        {
            PopulateServiceDatabaseTab();
            _dirtyTracker.IsDirty = false;
        }

        private void btnServiceDatabaseTestConnection_Click(object sender, EventArgs e)
        {
            Cursor = Cursors.WaitCursor;
            string connectionString = "";

            if (radServiceWindowsAuthentication.Checked)
            {
                connectionString = "Data Source=" + cboServiceSQLServer.Text + ";Initial Catalog=" + cboServiceDatabase.Text + ";Integrated Security=SSPI;";
            }
            else
            {
                connectionString = "Data Source=" + cboServiceSQLServer.Text + ";Initial Catalog=" + cboServiceDatabase.Text + ";User Id=" + txtServiceDatabaseUserName.Text + ";Password=" + txtServiceDatabasePassword.Text + ";";
            }

            SQLCommunicator sc = new SQLCommunicator();
            if (sc.TestConnection(connectionString) == true)
            {
                MessageBox.Show("Connection Success!", "Successful Connection", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            Cursor = Cursors.Default;
        }

        #endregion

        #region Hub Settings
        private void btnHubUndo_Click(object sender, EventArgs e)
        {
            PopulateVOEISHubTab();
            _dirtyTracker.IsDirty = false;
        }
        #endregion

        #region Notification Settings
        private void cbxMailEnabled_CheckedChanged(object sender, EventArgs e)
        {
            if (cbxMailEnabled.Checked)
            {
                //enable all of the controls in this tab
                txtSMTPServer.Enabled = true;
                txtPort.Enabled = true;
                txtSender.Enabled = true;
                cbxSSL.Enabled = true;
                txtRecipients.Enabled = true;
                cbxUseAuthentication.Enabled = true;
                txtEmailUserName.Enabled = true;
                txtEmailPassword.Enabled = true;
                cbxUseAuthentication_CheckedChanged(sender, e);               

            }
            else
            {
                //disable all of the controls in this tab
                txtSMTPServer.Enabled = false;
                txtPort.Enabled = false;
                txtSender.Enabled = false;
                cbxSSL.Enabled = false;
                txtRecipients.Enabled = false;
                cbxUseAuthentication.Enabled = false;
                txtEmailUserName.Enabled = false;
                txtEmailPassword.Enabled = false;
                cbxUseAuthentication_CheckedChanged(sender, e);
            }
        }

        private void cbxUseAuthentication_CheckedChanged(object sender, EventArgs e)
        {
            if (cbxUseAuthentication.Checked)
            {
                txtEmailUserName.Enabled = true;
                txtEmailPassword.Enabled = true;
            }
            else
            {
                txtEmailPassword.Enabled = false;
                txtEmailUserName.Enabled = false;
            }
        }

        //TODO: I might want to move this into another class for mailings
        private void btnEmailSendTestMessage_Click(object sender, EventArgs e)
        {
            SmtpClient client = new SmtpClient(txtSMTPServer.Text);
            client.Port = Convert.ToInt32(txtPort.Text);
            client.EnableSsl = cbxSSL.Checked;

            if (cbxUseAuthentication.Checked)
            {
                System.Net.NetworkCredential creds = new System.Net.NetworkCredential(txtEmailUserName.Text, txtEmailPassword.Text);
                client.Credentials = creds;
            }

            MailMessage msg = new MailMessage(txtSender.Text, txtRecipients.Text);

            msg.Subject = "Test notification from the VOEIS Hub Push Service Manager";
            msg.Body = "Your settings are correct!";

            try
            {
                client.Send(msg);
                MessageBox.Show("Check your inbox!", "Test message sent", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString(), "Error sending test mail", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                client = null;
                msg = null;
            }
        }

        #endregion

        #region PopulateTabs
        //TODO: This should be run in a separate thread.

        public void PopulateConfiguration()
        {
            //TODO: Run this in a separate thread
            try
            {

                PopulateServiceControlTab();
                PopulateServiceDatabaseTab();
                PopulateVOEISHubTab();
                PopulatePushResultsTab();
                PopulateNotificationsTab();

                _dirtyTracker.IsDirty = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
        }

        private void PopulateServiceControlTab()
        {
            VOEISHubAPI hubAPI = new VOEISHubAPI();

            //Service Control Tab
            //Push Interval
            decimal totalTime = Convert.ToInt32(hubAPI.PushInterval);
            cboDays.SelectedItem = Math.Floor(totalTime / 86400000).ToString();
            cboHours.SelectedItem = Math.Floor(((totalTime / 86400000) - Math.Floor(totalTime / 86400000)) * 24).ToString();
            cboMinutes.SelectedItem = Math.Round(((((totalTime / 3600000) - Math.Floor(totalTime / 3600000)) * 60) / 5) * 5).ToString();

            //Hub Timeout
            cbxHubTimeout.SelectedItem = (string)((Convert.ToInt32(hubAPI.HubTimeout)/60)/1000).ToString();

            //Service Log
            StartEventLogThread();

            //Reset the dirty property
            _dirtyTracker.IsDirty = false;          
        }

        private void PopulateServiceDatabaseTab()
        {

            SQLCommunicator sqlComm = new SQLCommunicator();

            //Push Service Database Tab
            //Server
            cboServiceSQLServer.Text = sqlComm.ServiceSQLServer;
            
            //Database
            cboServiceDatabase.Text = sqlComm.ServiceDatabase;
            
            //Authentication
            if (sqlComm.ServiceAuthentication == "Windows")
            {
                radServiceWindowsAuthentication.Checked = true;
            }
            else
            {
                radServiceWindowsAuthentication.Checked = false;
            }

            //User Name
            txtServiceDatabaseUserName.Text = sqlComm.ServiceUserName;

            //Password
            txtServiceDatabasePassword.Text = sqlComm.ServicePassword;

            //DB Timeout
            cbxDBTimeout.SelectedItem = string.Format("{0}", (sqlComm.ServiceDBTimeout)/60);

            //Max Records
            txtServiceMaxRecords.Text = sqlComm.ServiceMaxRecords.ToString();

            //Reset the dirty property
            _dirtyTracker.IsDirty = false;
        }

        private void PopulateVOEISHubTab()
        {
            //Property binding against the class
            VOEISHubAPI hubAPI = new VOEISHubAPI();

            //VOEIS Hub Tab
            //API Key
            txtAPIKey.Text = hubAPI.APIKey;

            //Reset the dirty property
            _dirtyTracker.IsDirty = false;
        }

        private void PopulatePushResultsTab()
        {
            //Set up
            SQLCommunicator sqlComm = new SQLCommunicator();
            
            //Check that the default server has been replaced
            if (!sqlComm.ServiceConnectionString.Contains("YourServer\\YourDatabase"))
            {

                //Get a dictionary containing the datasets and syncID's
                Dictionary<string, string> dictionary = new Dictionary<string, string>();
                dictionary = sqlComm.ListDataSets();

                //bind the dictionary to the combobox
                if (dictionary.Count > 0)
                {
                    cboPushResultsDataStreams.DataSource = new BindingSource(dictionary, null);
                    cboPushResultsDataStreams.DisplayMember = "Value";
                    cboPushResultsDataStreams.ValueMember = "Key";
                    cboPushResultsDataStreams_SelectedIndexChanged(sqlComm, null);
                }
            }
            else
            {
                MessageBox.Show("It appears that you have not updated your service settings." + Environment.NewLine + 
                    "Be sure to do so and save your settings before starting your service.", "Service Initialization", 
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

            _dirtyTracker.IsDirty = false;
        }

        private void PopulateNotificationsTab()
        {
            //Property binding against the class
            ServiceNotifications svcNotify = new ServiceNotifications();

            //Notifications Tab
            //Mail Enabled
            cbxMailEnabled.Checked = svcNotify.SMTPMailEnabled;

            //SMTP Server
            txtSMTPServer.Text = svcNotify.SMTPServer;

            //SMTP Port
            txtPort.Text = string.Format("{0}", svcNotify.SMTPPort);

            //SMTP Sender
            txtSender.Text = svcNotify.SMTPSender;

            //SMTP Recipients
            txtRecipients.Text = svcNotify.SMTPRecipients;

            //SSL Enabled
            cbxSSL.Checked = svcNotify.SMTPSSLEnabled;

            //Requires Authentication
            cbxUseAuthentication.Checked = svcNotify.SMTPRequiresAuthentication;

            //SMTP Username
            txtEmailUserName.Text = svcNotify.SMTPUserName;

            //SMTP Password
            txtEmailPassword.Text = svcNotify.SMTPPassword;

            //Enable or disable appropriately
            cbxMailEnabled_CheckedChanged(cbxMailEnabled, EventArgs.Empty);

            //Reset the dirty property
            _dirtyTracker.IsDirty = false;
        }

        public void LoadConfiguration(string TemplatePath)
        {
            try
            {
                LoadServiceControlTab(TemplatePath);
                LoadServiceDatabaseTab(TemplatePath);
                LoadVOEISHubTab(TemplatePath);
                LoadPushResultsTab(TemplatePath);
                LoadNotificationsTab(TemplatePath);

                _dirtyTracker.IsDirty = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
        }

        private void LoadServiceControlTab(string TemplatePath)
        {
            VOEISHubAPI hubAPI = new VOEISHubAPI();
            hubAPI.LoadAPISettings(TemplatePath);

            //Service Control Tab
            //Push Interval
            decimal totalTime = Convert.ToInt32(hubAPI.PushInterval);
            cboDays.SelectedItem = Math.Floor(totalTime / 86400000).ToString();
            cboHours.SelectedItem = Math.Floor(((totalTime / 86400000) - Math.Floor(totalTime / 86400000)) * 24).ToString();
            cboMinutes.SelectedItem = Math.Round(((((totalTime / 3600000) - Math.Floor(totalTime / 3600000)) * 60) / 5) * 5).ToString();

            //Hub Timeout
            cbxHubTimeout.SelectedItem = (string)((Convert.ToInt32(hubAPI.HubTimeout)/60)/1000).ToString();

            //Service Log
            StartEventLogThread();

            //Reset the dirty property
            _dirtyTracker.IsDirty = false;  
        }

        private void LoadServiceDatabaseTab(string TemplatePath)
        {
            SQLCommunicator sqlComm = new SQLCommunicator();

            sqlComm.LoadDatabaseSettings(TemplatePath);

            //Push Service Database Tab
            //Server
            cboServiceSQLServer.Text = sqlComm.ServiceSQLServer;
            
            //Database
            cboServiceDatabase.Text = sqlComm.ServiceDatabase;
            
            //Authentication
            if (sqlComm.ServiceAuthentication == "Windows")
            {
                radServiceWindowsAuthentication.Checked = true;
            }
            else
            {
                radServiceWindowsAuthentication.Checked = false;
            }

            //User Name
            txtServiceDatabaseUserName.Text = sqlComm.ServiceUserName;

            //Password
            txtServiceDatabasePassword.Text = sqlComm.ServicePassword;

            //DB Timeout
            cbxDBTimeout.SelectedItem = string.Format("{0}", (sqlComm.ServiceDBTimeout)/60);

            //Max Records
            txtServiceMaxRecords.Text = sqlComm.ServiceMaxRecords.ToString();

            //Reset the dirty property
            _dirtyTracker.IsDirty = false;
        }

        private void LoadVOEISHubTab(string TemplatePath)
        {
            VOEISHubAPI hubAPI = new VOEISHubAPI();

            hubAPI.LoadAPISettings(TemplatePath);

            //VOEIS Hub Tab
            //API Key
            txtAPIKey.Text = hubAPI.APIKey;

            //Reset the dirty property
            _dirtyTracker.IsDirty = false;
        }

        private void LoadPushResultsTab(string TemplatePath)
        {
            SQLCommunicator sqlComm = new SQLCommunicator();

            //Get a dictionary containing the datasets and syncID's
            Dictionary<string, string> dictionary = new Dictionary<string, string>();
            sqlComm.LoadDatabaseSettings(TemplatePath);
            dictionary = sqlComm.ListDataSets();

            //disable the event handler
            cboPushResultsDataStreams.SelectedIndexChanged -= cboPushResultsDataStreams_SelectedIndexChanged;
            //bind the dictionary to the combobox
            if (dictionary.Count > 0)
            {
                cboPushResultsDataStreams.DataSource = new BindingSource(dictionary, null);
                cboPushResultsDataStreams.DisplayMember = "Value";
                cboPushResultsDataStreams.ValueMember = "Key";
                //cboPushResultsDataStreams_SelectedIndexChanged(sqlComm, null);
            }
            cboPushResultsDataStreams.SelectedIndexChanged += cboPushResultsDataStreams_SelectedIndexChanged;
            _dirtyTracker.IsDirty = false;
        }

        private void LoadNotificationsTab(string TemplatePath)
        {
            //Property binding against the class
            ServiceNotifications svcNotify = new ServiceNotifications();
            svcNotify.LoadServiceNotifications(TemplatePath);

            //Notifications Tab
            //Mail Enabled
            cbxMailEnabled.Checked = svcNotify.SMTPMailEnabled;

            //SMTP Server
            txtSMTPServer.Text = svcNotify.SMTPServer;

            //SMTP Port
            txtPort.Text = string.Format("{0}", svcNotify.SMTPPort);

            //SMTP Sender
            txtSender.Text = svcNotify.SMTPSender;

            //SMTP Recipients
            txtRecipients.Text = svcNotify.SMTPRecipients;

            //SSL Enabled
            cbxSSL.Checked = svcNotify.SMTPSSLEnabled;

            //Requires Authentication
            cbxUseAuthentication.Checked = svcNotify.SMTPRequiresAuthentication;

            //SMTP Username
            txtEmailUserName.Text = svcNotify.SMTPUserName;

            //SMTP Password
            txtEmailPassword.Text = svcNotify.SMTPPassword;

            //Enable or disable appropriately
            cbxMailEnabled_CheckedChanged(cbxMailEnabled, EventArgs.Empty);

            //Reset the dirty property
            _dirtyTracker.IsDirty = false;
        }

        private void cboPushResultsDataStreams_DropDown(object sender, EventArgs e)
        {
            PopulatePushResultsTab();
        }

        //TODO: Write a class to parse the JSON
        //TODO: Change this so that it reads from the inputs rather than the config, so a user can change the configuration and test it.
        private void cboPushResultsDataStreams_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (_dirtyTracker.IsDirty == false)
            {
                SQLCommunicator sqlComm = new SQLCommunicator();

                //Deserialize the json string
                //Example: {"total_records_saved":8,"last_record":{"created_at":"2011-03-07T20:20:28-07:00","timestamp":"2011-01-19T13:00:00-07:00","updated_at":"2011-03-07T20:20:28-07:00","published":false,"units":"NA","string_value":"6.12","id":42,"sensor_id":4,"value":6.12,"vertical_offset":-0.512},"success":"File was parsed succesfully.","total_rows_parsed":8}
                string SyncID = cboPushResultsDataStreams.SelectedItem.ToString();
                KeyValuePair<string, string> kvp = (KeyValuePair<string, string>)cboPushResultsDataStreams.SelectedItem;
                string json = sqlComm.GetPushResults(Int32.Parse(kvp.Key));

                if (json.Length > 0)
                {
                    JavaScriptSerializer serializer = new JavaScriptSerializer();

                    try
                    {
                        IDictionary<string, object> JSONDictionary = serializer.Deserialize<IDictionary<string, object>>(json);
                        txtPushResults.Text = "";
                        txtPushResults.Text = ParseJSON(JSONDictionary);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message.ToString());
                    }
                }
            }
            else
            {
                MessageBox.Show("You have changes that must be changed or undone before using this feature.");
            }

            //Reset the dirty property
            _dirtyTracker.IsDirty = false;
        }


        #region EventLog
        private void StartEventLogThread()
        {
            //Start a thread to run the event log in
            System.Threading.Thread evtLogThread = new System.Threading.Thread(new System.Threading.ThreadStart(PopulateEventLogGrid));
            evtLogThread.Start(); 
            _evtLogThreadCount++;           
        }

        private void PopulateEventLogGrid()
        {
            pbEventLogLoading.BeginInvoke((MethodInvoker)delegate() { pbEventLogLoading.Visible = true; });

            object query = QueryEventLog();

            if (!_closeRequested)
            {
                dataGridView1.BeginInvoke((MethodInvoker)delegate() { dataGridView1.DataSource = query; });

                pbEventLogLoading.BeginInvoke((MethodInvoker)delegate() { pbEventLogLoading.Visible = false; });
            }

            Invoke(new EventHandler(EventLogClose));
        }

        private object QueryEventLog()
        {
            System.Diagnostics.EventLog evtLog = new System.Diagnostics.EventLog();
            evtLog.Log = "Application";
            evtLog.MachineName = System.Environment.MachineName.ToString();

            try
            {
                var query = from EventLogEntry el in evtLog.Entries
                            where el.Source == "VOEIS Hub Push Service"
                            orderby el.TimeGenerated descending
                            select new
                            {
                                Time = el.TimeGenerated,
                                Source = el.Source,
                                Message = el.Message
                            };

                return query.ToList();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                object query = null;
                return query;
            }
        }

        private void EventLogClose(object o, EventArgs e)
        {
            _evtLogThreadCount--;

            if (_closeRequested)
            {
                this.Close();
            }
        }
        #endregion

        //TODO: Write a class for the json parsing.
        private string ParseJSON(IDictionary<string, object> JSONData)
        {
            string strJSON = "";
            try
            {
                foreach (KeyValuePair<string, object> kvp in JSONData)
                {
                    if (kvp.Value != null)
                    {

                        if (!(kvp.Value.GetType() == typeof(System.Collections.Generic.Dictionary<string, object>)))
                        {
                            //There can be null values in the kvp.value slot, and I need to account for that
                            strJSON = strJSON + kvp.Key.ToString() + ": ";

                            if (kvp.Value != null)
                            {
                                strJSON += kvp.Value.ToString();
                            }
                            else
                            {
                                strJSON += "";
                            }

                            strJSON += System.Environment.NewLine;
                        }
                        else
                        {
                            strJSON += ParseJSON((IDictionary<string, object>)kvp.Value);
                        }
                    }
                    else
                    {
                        strJSON += kvp.Key.ToString() + ": null" + System.Environment.NewLine;
                    }

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }

            return strJSON;
        }

        private void btnRefreshEventLog_Click(object sender, EventArgs e)
        {
            StartEventLogThread();
        }

        #endregion

        #region SaveTabs

        private void SaveServiceControlTab()
        {
            //Create our dictionary
            Dictionary<string, string> ServiceSettings = new Dictionary<string, string>();

            //Populate our dictionary
            int totalTime = (Convert.ToInt32(cboDays.SelectedItem)*86400000) + (Convert.ToInt32(cboHours.SelectedItem)*3600000) + (Convert.ToInt32(cboMinutes.SelectedItem)*60000);
            
            //Push Interval - make sure that the interval is greater than 0
            if (totalTime > 0)
            {
                ServiceSettings.Add("DataCheckInterval", Convert.ToString(totalTime));
            }
            else
            {
                MessageBox.Show("You must set an interval of 5 minutes or greater.\n Save Aborted.", "Invalid Interval", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                PopulateServiceControlTab();
            }
            ServiceSettings.Add("HubTimeout", string.Format("{0}", (int.Parse(cbxHubTimeout.Text))*60000));

            //Get a handle for our ServiceConfigurationManager Class
            ServiceConfigurationManager scm = new ServiceConfigurationManager();

            //Save the settings
            scm.SaveSectionSettings(ServiceSettings);

            //Reset the dirty tracker
            _dirtyTracker.IsDirty = false;
                        
        }

        private void SaveServiceDatabaseTab()
        {
            //Create our dictionary
            Dictionary<string, string> DatabaseSettings = new Dictionary<string, string>();

            //Populate our Dictionary
            DatabaseSettings.Add("ServiceSQLServer", cboServiceSQLServer.Text);
            DatabaseSettings.Add("ServiceDatabase", cboServiceDatabase.Text);
            if (radServiceWindowsAuthentication.Checked)
            {
                DatabaseSettings.Add("ServiceAuthentication", "Windows");
            }
            else
            {
                DatabaseSettings.Add("ServiceAuthentication", "SQL");
            }
            DatabaseSettings.Add("ServiceUserName", txtServiceDatabaseUserName.Text);
            DatabaseSettings.Add("ServicePassword", txtServiceDatabasePassword.Text);
            DatabaseSettings.Add("DBTimeout", string.Format("{0}",int.Parse(cbxDBTimeout.Text)*60));
            DatabaseSettings.Add("ServiceMaxRecords", txtServiceMaxRecords.Text);

            //Get a handle for our ServiceConfigurationManager Class
            ServiceConfigurationManager scm = new ServiceConfigurationManager();

            //Save the settings
            scm.SaveSectionSettings(DatabaseSettings);

            //Reset the dirty tracker
            _dirtyTracker.IsDirty = false;
        }

        private void SaveVOEISHubTab()
        {
            //Create our dictionary
            Dictionary<string, string> APISettings = new Dictionary<string, string>();

            //Populate our dictionary
            APISettings.Add("APIKey", txtAPIKey.Text);

            //Get a handle for our ServiceConfigurationManager Class
            ServiceConfigurationManager scm = new ServiceConfigurationManager();

            //Save the settings
            scm.SaveSectionSettings(APISettings);

            //Reset the dirty tracker
            _dirtyTracker.IsDirty = false;            
        }

        private void SaveNotificationsTab()
        {
            //Create our dictionary
            Dictionary<string, string> NotificationSettings = new Dictionary<string, string>();

            //Populate our dictionary
            NotificationSettings.Add("MailEnabled", cbxMailEnabled.Checked.ToString());
            NotificationSettings.Add("MailServer", txtSMTPServer.Text);
            NotificationSettings.Add("MailPort", txtPort.Text);
            NotificationSettings.Add("ServiceEmail", txtSender.Text);
            NotificationSettings.Add("MailRecipients", txtRecipients.Text);
            NotificationSettings.Add("MailSSL", cbxSSL.Checked.ToString());
            NotificationSettings.Add("MailAuthenticate", cbxUseAuthentication.Checked.ToString());
            NotificationSettings.Add("MailUserName", txtEmailUserName.Text);
            NotificationSettings.Add("MailPassword", txtEmailPassword.Text);

            //Get a handle for our ServiceConfigurationManager class
            ServiceConfigurationManager scm = new ServiceConfigurationManager();

            //Save the settings
            scm.SaveSectionSettings(NotificationSettings);

            //Reset the dirty tracker
            _dirtyTracker.IsDirty = false;            
        }

        private void SaveConfiguration()
        {
            try
            {
                //Stop Service and wait for stop response
                ServiceController myController = new ServiceController("VOEIS Hub Push Service", System.Environment.MachineName.ToString());
                ServiceControllerStatus initStatus = myController.Status;
                if (initStatus == ServiceControllerStatus.Running)
                {
                    myController.Stop();
                }

                //TODO: I need to check the controller state here before moving on, otherwise I get an error when trying to start the service.
                SaveServiceControlTab();
                //SaveObservationsDatabaseTab(configPath);
                SaveServiceDatabaseTab();
                SaveVOEISHubTab();
                SaveNotificationsTab();
                _dirtyTracker.IsDirty = false;

                //Restart service if required
                if (initStatus == ServiceControllerStatus.Running)
                {
                    myController.Start();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString(), "Error saving configuration.", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        #endregion

        private void txtServiceMaxRecords_Leave(object sender, EventArgs e)
        {
            int parseResult = 0;

            if (int.TryParse(((TextBox)sender).Text, out parseResult) == false)
            {
                MessageBox.Show("You must enter an integer for the number of records that you would like to send in each push.", "Parser Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

                ServiceConfigurationManager scm = new ServiceConfigurationManager();
                txtServiceMaxRecords.Text = scm.ReadApplicationSetting("ServiceMaxRecords", scm.ApplicationConfigPath);
            }
        }

    }
}


